#pragma once
#include <ostream>
template <typename T>
class Node {
public:
	template <typename T>
	friend class arrayList;
	template <typename T>
	friend class sparseMatrix;
	Node();
	Node(int rows, int cols, T value);
	~Node();
	void setValue(const int rows, const int cols,const T& value);
private:
	int rows;
	int cols;
	T value;
	Node<T>* next;
};
template <typename T>
Node<T>::Node() {
	rows = 0;
	cols = 0;
	value = 0;
	next = nullptr;
}
template <typename T>
Node<T>::Node(int rows, int cols, T value) {
	this->rows = rows;
	this->cols = cols;
	this->value = value;
	next = nullptr;
}
template <typename T>
Node<T>::~Node(){

}
template <typename T>
void Node<T>::setValue(const int rows, const int cols,const T& value) {
	this->value = value;
}
template <typename T>
class arrayList {
public:
	arrayList(int maxSize);
	arrayList(int maxSize, Node<T>* head);
	arrayList(const arrayList<T>& list);
	~arrayList();
	Node<T>* getHead();
	void setMaxSize(int maxSize);
	int getMaxSize();
	void clear();
	bool deletebyPosition(const int i, const int j);
	int sizeofList();
	bool isEmpty();
	bool push_back(int rows, int cols, T value);
	bool getValue(const int rows, const int cols, T& value);
	bool setValue(const int rows, const int cols, T value);
	void output(std::ostream& out);
private:
	int maxSize;
	Node<T>* head;
};
template <typename T>
arrayList<T>::arrayList(int maxSize) {
	this->maxSize = maxSize;
	head = new Node<T>;
}
template <typename T>
arrayList<T>::arrayList(int maxSize,Node<T>* head) {
	this->maxSize = maxSize;
	this->head = new Node<T>;
	this->head = head;
}
template <typename T>
arrayList<T>::arrayList(const arrayList<T>& list){
	maxSize = list.maxSize;
	head = new Node<T>;
	Node<T>* newlist = head;
	Node<T>* oldlist = list.head->next;
	while (oldlist != nullptr) {
		newlist->next = new Node<T>(oldlist->rows, oldlist->cols, oldlist->value);
		oldlist = oldlist->next;
		newlist = newlist->next;
	}
	newlist->next = nullptr;

}
template <typename T>
arrayList<T>::~arrayList() {
	delete head;
}
template <typename T>
Node<T>* arrayList<T>::getHead(){
	return head;
}
template <typename T>
void arrayList<T>::setMaxSize(int maxSize) {
	this->maxSize = maxSize;
}
template <typename T>
int arrayList<T>::getMaxSize() {
	return maxSize;
}
template <typename T>
void arrayList<T>::clear() {
	while (head->next != nullptr) {
		Node<T>* temp = head->next->next;
		delete head->next;
		head->next = temp;
	}
}
template <typename T>
bool arrayList<T>::deletebyPosition(const int i, const int j) {
	Node<T>* currentNode = head;
	while (currentNode->next != nullptr) {
		if (currentNode->next->rows == i && currentNode->next->cols == j) {
			Node<T>* temp = currentNode;
			currentNode = currentNode->next;
			temp->next = currentNode->next;
			delete currentNode;
			return true;
		}
		currentNode = currentNode->next;
	}
	if (currentNode->rows == i && currentNode->cols == j) {
		delete currentNode;
		currentNode = nullptr;
		return true;
	}
	return false;
}
template <typename T>
bool arrayList<T>::isEmpty() {
	if (head->next == nullptr)
		return true;
	return false;
}
template <typename T>
int arrayList<T>::sizeofList(){
	int size = 0;
	Node<T>* currentNode = head;
	while (currentNode->next != nullptr) {
		size++;
		currentNode = currentNode->next;
	}
	return size;
}
template <typename T>
bool arrayList<T>::push_back(int rows, int cols, T value) {
	Node<T>* currentNode = head;
	while (currentNode->next != nullptr)
		currentNode = currentNode->next;
	currentNode->next = new Node<T>(rows, cols, value);
	return true;
}
template <typename T>
bool arrayList<T>::getValue(const int rows, const int cols, T& value) {
	Node<T>* currentNode = head->next;
	while (currentNode != nullptr) {
		if (currentNode->rows == rows && currentNode->cols == cols) {
			value = currentNode->value;
			return true;
		}
		currentNode = currentNode->next;
	}
	return false;
}
template <typename T>
bool arrayList<T>::setValue(const int i, const int j, T value) {
	T x;
	if (this->getValue(i, j, x)) {
		Node<T>* currentNode = head->next;
		while (currentNode != nullptr) {
			if (currentNode->rows == i && currentNode->cols == j) {
				currentNode->value = value;
				return true;
			}
			currentNode = currentNode->next;
		}
		return true;
	}
	else {
		this->push_back(i, j, value);
		return true;
	}
	return false;
}
template <typename T>
void arrayList<T>::output(std::ostream& out) {
	Node<T>* currentNode = head->next;
	while (currentNode != nullptr) {
		out <<"row = " <<currentNode->rows << " " << "col = " << currentNode->cols << " " << "value = " << currentNode->value << '\n';
		currentNode = currentNode->next; 
	}
	return;
}
